package com.stone.design.mode.state.spring;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.StateMachineContext;
import org.springframework.statemachine.StateMachinePersist;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.StateMachineConfig;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.*;
import org.springframework.statemachine.config.common.annotation.AnnotationBuilder;
import org.springframework.statemachine.persist.DefaultStateMachinePersister;
import org.springframework.statemachine.support.DefaultStateMachineContext;

import java.util.EnumSet;

/**
 * 订单状态机配置
 * 构造一个状态机有两种方式
 * 1、使用构造器工具类 stateMachineBuilder.builder() (构造吗欧式：硬编码)
 * 2、使用Java config 的形式，扩展StateMachineConfigurerAdapter<states,events> 类，并覆盖configure方法，完成状态机配置
 *
 * @author wenpan 2022/06/18 17:31
 */
@Configuration
@EnableStateMachine(name = "orderStateMachine")
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderStateChangeEvent> {

    public OrderStateMachineConfig() {
        super();
    }

    /**
     * 配置状态机初始状态
     */
    @Override
    public void configure(StateMachineStateConfigurer<OrderStatus, OrderStateChangeEvent> states) throws Exception {
        states
                .withStates()
                .initial(OrderStatus.WAITE_PAYMENT)
                .states(EnumSet.allOf(OrderStatus.class));
    }

    /**
     * 配置状态转换事件关系
     *
     * @param transitions 转换节点，要配置每个转换节点的 原状态 ---> 目标状态
     * @author wenpan 2022/6/18 5:46 下午
     */
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderStateChangeEvent> transitions) throws Exception {
        transitions
                // 配置从 等待支付状态到 等待发货状态 并配置转换事件
                .withExternal().source(OrderStatus.WAITE_PAYMENT).source(OrderStatus.WAIT_DELIVER).event(OrderStateChangeEvent.PAYED)
                .and()
                .withExternal().source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_RECEIVE).event(OrderStateChangeEvent.DELIVERY)
                .and()
                .withExternal().source(OrderStatus.WAIT_RECEIVE).target(OrderStatus.FINISH).event(OrderStateChangeEvent.RECEIVED);
    }

    /**
     * 持久化配置(该类由spring托管)
     * 实际使用中，这里可以配合Redis等进行持久化操作
     */
    @Bean
    public DefaultStateMachinePersister persister() {
        return new DefaultStateMachinePersister<>(new StateMachinePersist<Object, Object, Order>() {

            @Override
            public void write(StateMachineContext<Object, Object> stateMachineContext, Order order) throws Exception {
                // todo 此处可以对order对象进行 redis / 数据库 进行持久化操作

            }

            @Override
            public StateMachineContext<Object, Object> read(Order order) throws Exception {
                // TODO 这里从数据库或Redis中读取order的信息，存到context上下文中，并绑定下一个要处理的事件
                return new DefaultStateMachineContext<>(order.getStatus(), null, null, null);
            }

        });

    }

    // ===================================下面的方法不进行覆写===================================

    @Override
    public void configure(StateMachineConfigBuilder<OrderStatus, OrderStateChangeEvent> config) throws Exception {
        super.configure(config);
    }

    @Override
    public void configure(StateMachineModelConfigurer<OrderStatus, OrderStateChangeEvent> model) throws Exception {
        super.configure(model);
    }

    @Override
    public void configure(StateMachineConfigurationConfigurer<OrderStatus, OrderStateChangeEvent> config) throws Exception {
        super.configure(config);
    }


    @Override
    public boolean isAssignable(AnnotationBuilder<StateMachineConfig<OrderStatus, OrderStateChangeEvent>> builder) {
        return super.isAssignable(builder);
    }
}
